package com.finance.framework.shiro;

import com.finance.base.enums.StateEnum;
import com.finance.system.bean.pojo.Menu;
import com.finance.system.bean.pojo.Role;
import com.finance.system.service.IMenuService;
import com.finance.system.service.IRoleService;
import com.finance.util.DateUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Service
public class ShiroConfig implements ApplicationContextAware{
	protected  final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);

	private Properties fixRules = new Properties();
	private ApplicationContext context;
	@Autowired(required = false)
	private IRoleService roleService;
	@Autowired(required = false)
	private IMenuService menuService;
	public ShiroConfig(){
		InputStream is = null;
		try {
			is = ShiroConfig.class.getResourceAsStream("/properties/shiro.properties");
			if(is !=null) {
                fixRules.load(is);
            }
		} catch (IOException e) {
			logger.error(e.getMessage(),e);
		}finally {
			try{
				if(is!=null) {
                    is.close();
                }
			}catch (IOException e){
				logger.error(e.getMessage(),e);
			}
		}
	}

	/**
	 * 菜单权限校验
	 * @return
	 */
	public String loadFilterChainDefinitions(){
		StringBuffer sb = new StringBuffer();
		Iterator<Object> iterator = fixRules.keySet().iterator();
		while(iterator.hasNext()){
			String key = (String) iterator.next();
			String value = fixRules.getProperty(key);
			sb.append(key + " = " + value +"\r\n");
		}
		sb.append(this.getDynamicRules());
		sb.append("/**=anon\r\n");
		return sb.toString();
	}
	/**
     * 获取菜单权限 规则
     * */
	private String getDynamicRules(){
		List<Menu> menus = this.menuService.listAll();
		List<Role> roleList = this.roleService.listAll();
		if(CollectionUtils.isEmpty(menus)&&CollectionUtils.isEmpty(roleList)) {
            return "";
        }
		/**
		 * 组装一个map  key url: value set of roleId
		 */
		Map<String,Set<String>> mapping = new HashMap<String,Set<String>>();
		for(Menu menu : menus){
			if(menu.getState()==StateEnum.Valid.getState()) {
                if (StringUtils.isNotBlank(menu.getUrl())) {
                    mapping.put(menu.getUrl(), new HashSet());
                }
            }
		}
		for (Role role:roleList) {
			List<Menu> menuList = role.getMenuList();
			if(menuList == null|| menuList.isEmpty()){
				continue;
			}
			for(Menu menu : menuList){
				if(StringUtils.isNotEmpty(menu.getUrl())){
					Set<String> roleIds=mapping.get(menu.getUrl());
					if(roleIds == null){
						roleIds = new HashSet<String>();
					}
					if(menu.getState()==StateEnum.Valid.getState()){
						roleIds.add(role.getId().toString());
					}
					mapping.put(menu.getUrl(),roleIds);
				}
			}
		}
		StringBuilder stringBuilder = new StringBuilder();
		for (Map.Entry<String, Set<String>> entry :mapping.entrySet()){
			String url=entry.getKey();
			Set<String> roleIds=entry.getValue();

			StringBuilder stringBuilder2 = new StringBuilder();
			stringBuilder2.append("roles[");
			if(CollectionUtils.isEmpty(roleIds)) {
                return "";
            }
			for(String roleId : roleIds){
				stringBuilder2.append(roleId);
				stringBuilder2.append(",");
			}
			if(!roleIds.isEmpty()) {
                stringBuilder2.deleteCharAt(stringBuilder2.length() - 1);
            }
			stringBuilder2.append("]\r\n");

			stringBuilder.append(url.split("\\?")[0]);
			stringBuilder.append("=");
			stringBuilder.append(stringBuilder2.toString());

		}

		return stringBuilder.toString();
	}

	/**
	 * 重设角色权限
	 */
	public void reload(){
		ShiroFilterFactoryBean shiroFilterFactoryBean = (ShiroFilterFactoryBean)this.context.getBean(ShiroFilterFactoryBean.class);
		AbstractShiroFilter shiroFilter = null;
		try {
			shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
		} catch (Exception e) {
			throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
		}
		PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
		DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
		// 清空老的权限控制
		manager.getFilterChains().clear();
		shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
		shiroFilterFactoryBean.setFilterChainDefinitions(loadFilterChainDefinitions());
		shiroFilterFactoryBean.setFilterChainDefinitions(this.loadFilterChainDefinitions());
		//重设权限
		Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
		for (Map.Entry<String, String> entry : chains.entrySet()) {
			String url = entry.getKey();
			String chainDefinition = entry.getValue().trim().replace(" ", "");
			manager.createChain(url, chainDefinition);
		}
	}
	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.context = applicationContext;
	}
}
